#pragma once
#include "VulkanDevice.h"
#include "Runtime/CGI/CGIRenderPass.h"
#include "Runtime/CGI/CGIResource.h"
#include "Runtime/CGI/GraphicsPipelineStateInitializer.h"

namespace Alice
{
    class VulkanRenderTargetLayout
    {
    public:
        VkAttachmentReference ColorReferences[MaxSimultaneousRenderTargets];
        VkAttachmentReference DepthReference;
		VkAttachmentReferenceStencilLayout StencilReference;

        // Depth goes in the "+1" slot, Depth resolve goes in the "+2 slot", and the Shading Rate texture goes in the "+3" slot.
        VkAttachmentDescription Desc[MaxSimultaneousRenderTargets * 2 + 3];
    	VkAttachmentDescriptionStencilLayout StencilDesc;

        uint8 NumAttachmentDescriptions;
        uint8 NumColorAttachments;
        uint8 bHasDepthStencil;
        uint8 NumUsedClearValues;
		ESubpassHint SubpassHint = ESubpassHint::None;
    	union
    	{
    		VkOffset3D Offset3D;
    		VkOffset2D Offset2D;
    	} Offset;

    	union
    	{
    		VkExtent3D	Extent3D;
    		VkExtent2D	Extent2D;
    	} Extent;
    	VulkanRenderTargetLayout(const FGraphicsPipelineStateInitializer& Initializer);
    	VulkanRenderTargetLayout(VulkanDevice& InDevice, const CGIRenderPassInfo* RPInfo, VkImageLayout CurrentDepthLayout, VkImageLayout CurrentStencilLayout);
    	inline const VkOffset2D& GetOffset2D() const { return Offset.Offset2D; }
    	inline const VkOffset3D& GetOffset3D() const { return Offset.Offset3D; }
    	inline const VkExtent2D& GetExtent2D() const { return Extent.Extent2D; }
    	inline const VkExtent3D& GetExtent3D() const { return Extent.Extent3D; }
		inline const ESubpassHint GetSubpassHint() const { return SubpassHint; }
    	inline uint32 GetNumAttachmentDescriptions() const { return NumAttachmentDescriptions; }
    	inline const VkAttachmentDescription* GetAttachmentDescriptions() const { return Desc; }
    	
    	inline const VkAttachmentReference* GetColorAttachmentReferences() const { return NumColorAttachments > 0 ? ColorReferences : nullptr; }
    	inline const VkAttachmentReference* GetDepthAttachmentReference() const { return bHasDepthStencil ? &DepthReference : nullptr; }
    	inline const VkAttachmentReferenceStencilLayout* GetStencilAttachmentReference() const { return bHasDepthStencil ? &StencilReference : nullptr; }
    	inline const VkAttachmentDescriptionStencilLayout* GetStencilDesc() const { return bHasDepthStencil ? &StencilDesc : nullptr; }
    	bool operator==(const VulkanRenderTargetLayout&inRenderTargetLayout)const;
    };
	class VulkanRenderPass
	{
	public:
		inline const VulkanRenderTargetLayout& GetLayout() const
		{
			return mLayout;
		}

		inline VkRenderPass GetHandle() const
		{
			return mRenderPass;
		}

		inline uint32 GetNumUsedClearValues() const
		{
			return mNumUsedClearValues;
		}

		friend class FVulkanRenderPassManager;
		friend class FVulkanPipelineStateCacheManager;

		VulkanRenderPass(VulkanDevice& Device, const VulkanRenderTargetLayout& RTLayout);
		~VulkanRenderPass();

		VulkanRenderTargetLayout	mLayout;
		VkRenderPass				mRenderPass;
		uint32						mNumUsedClearValues;
		VulkanDevice&			mDevice;
	};
}
